package com.wangsd.web.coupon.service.impl;

import com.alibaba.fastjson.JSON;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.github.binarywang.wxpay.bean.coupon.WxPayCouponSendRequest;
import com.github.binarywang.wxpay.bean.coupon.WxPayCouponSendResult;
import com.github.binarywang.wxpay.bean.request.WxPayRefundRequest;
import com.github.binarywang.wxpay.bean.request.WxPayUnifiedOrderRequest;
import com.github.binarywang.wxpay.bean.result.WxPayRefundResult;
import com.github.binarywang.wxpay.exception.WxPayException;
import com.wangsd.common.component.WxPayServer;
import com.wangsd.common.utils.PayUtil;
import com.wangsd.web.coupon.entity.*;
import com.wangsd.web.coupon.service.*;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.BufferedOutputStream;
import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.TimeUnit;

import static com.wangsd.common.enums.CommonStatic.LOGIN_TOKEN_TYPE_M;

@Service
@Slf4j
public class WxMiniPayServiceImpl implements WxMiniPayService {
    @Autowired
    WxPayServer wxPayServer;

    @Autowired
    CompanyService companyService;

    @Autowired
    TOrderService tOrderService;

    @Autowired
    ProductService productService;

    @Autowired
    ServiceBusinessService serviceBusinessService;

    @Autowired
    CouponService couponService;

    @Autowired
    StoreService storeService;

    @Autowired
    MerchantService merchantService;

    @Autowired
    MemberService memberService;

    @Autowired
    MemberCouponService memberCouponService;

    @Autowired
    IntegralDetailService integralDetailService;

    @Autowired
    BusinessCouponService businessCouponService;

    @Autowired
    StringRedisTemplate stringRedisTemplate;

    @Value("${notify_url}")
    private String notifyUrl;

    @Override
    @Transactional
    public synchronized Object wxPay(String address, Product product, String miniAppId, Member member, HttpServletRequest request) throws Exception {
        /*调用微信支付*/
        WxPayUnifiedOrderRequest requestParam = new WxPayUnifiedOrderRequest();
        //商品名称
        requestParam.setBody(product.getName());
        //订单编号
        String orderNo = System.currentTimeMillis() + "";
        requestParam.setOutTradeNo(orderNo);
        //支付金额
        requestParam.setTotalFee(product.getValue());
        //创建支付ip
        requestParam.setSpbillCreateIp(PayUtil.getIpAddr(request));
        //消息通知url
        requestParam.setNotifyUrl(this.notifyUrl + "/coupon/wxProduct/wxNotify");
        requestParam.setTradeType("JSAPI");
        requestParam.setProductId(product.getId() + "");
        //子商户id,需要通过productId从数据库product中查出来
        requestParam.setSubMchId(product.getSubMchId());
        requestParam.setSubOpenid(member.getMiniOpenid());
        requestParam.setSubAppId(miniAppId);
        Company company = companyService.selectByMiniAppid(miniAppId);

        Object object = wxPayServer.getWxPayService(company.getBusinessServiceId()).createOrder(requestParam);

        /*保存订单信息*/
        TOrder order = new TOrder();
        order.setOpenid(member.getMiniOpenid());
        order.setOutTradeNo(orderNo);
        order.setOrderStatus(0);
        order.setTradeType("1");
        order.setProductId(product.getId());
        order.setOrderTotalFee(product.getValue());
        order.setCode(product.getCode());
        order.setAddress(address);
        order.setProductName(product.getName());
        order.setProductPicUrl(product.getProductPicUrl());
        order.setCompanyId(company.getId());
        order.setBusinessServiceId(company.getBusinessServiceId());
        tOrderService.save(order);

        /*商品数量减一*/
        Product newProduct = new Product();
        newProduct.setId(product.getId());
        newProduct.setUsableProductCount(product.getUsableProductCount()-1);
        productService.updateById(newProduct);

        return object;
    }

    @Override
    public Object wxBusinessCouponPay(String address, BusinessCoupon businessCoupon, String miniAppId, Member member, HttpServletRequest request) throws Exception {
        /*调用微信支付*/
        WxPayUnifiedOrderRequest requestParam = new WxPayUnifiedOrderRequest();
        //商品名称
        requestParam.setBody(businessCoupon.getStockName());
        //订单编号
        String orderNo = System.currentTimeMillis() + "";
        requestParam.setOutTradeNo(orderNo);
        //支付金额
        requestParam.setTotalFee(businessCoupon.getValue());
        //创建支付ip
        requestParam.setSpbillCreateIp(PayUtil.getIpAddr(request));
        //消息通知url
        requestParam.setNotifyUrl(this.notifyUrl + "/coupon/wxProduct/wxBusinessCouponNotify");
        requestParam.setTradeType("JSAPI");
        requestParam.setProductId(businessCoupon.getId() + "");
        //子商户id,需要通过productId从数据库product中查出来
        requestParam.setSubMchId(businessCoupon.getBelongMerchant());
        requestParam.setSubOpenid(member.getMiniOpenid());
        requestParam.setSubAppId(miniAppId);
        Company company = companyService.selectByMiniAppid(miniAppId);

        Object object = wxPayServer.getWxPayService(company.getBusinessServiceId()).createOrder(requestParam);

        /*保存订单信息*/
        TOrder order = new TOrder();
        order.setOpenid(member.getMiniOpenid());
        order.setOutTradeNo(orderNo);
        order.setOrderStatus(0);
        order.setProductId(businessCoupon.getId()+"");
        order.setTradeType("30");
        order.setOrderTotalFee(businessCoupon.getValue());
        order.setCode(businessCoupon.getCode());
        order.setAddress(address);
        order.setProductName(businessCoupon.getStockName());
        order.setProductPicUrl(businessCoupon.getBusinessCouponPicUrl());
        order.setCompanyId(company.getId());
        order.setBusinessServiceId(company.getBusinessServiceId());
        tOrderService.save(order);

        /*商品数量减一*/
        BusinessCoupon newBusinessCoupon = new BusinessCoupon();
        newBusinessCoupon.setId(businessCoupon.getId());
        newBusinessCoupon.setUsableBusinessCouponCount(businessCoupon.getUsableBusinessCouponCount()-1);
        businessCouponService.updateById(newBusinessCoupon);

        Map<String,Object> resultMap = new HashMap<>();
        resultMap.put("outTradeNo",orderNo);
        resultMap.put("sign",object);

        return resultMap;
    }

    @Override
    public void wxNotify(HttpServletRequest request, HttpServletResponse response) throws Exception {
        BufferedOutputStream out = null;
        String resXml = "<xml>" + "<return_code><![CDATA[SUCCESS]]></return_code>"
                + "<return_msg><![CDATA[OK]]></return_msg>" + "</xml> ";
        BufferedReader br = new BufferedReader(new InputStreamReader(request.getInputStream()));
        String line;
        StringBuilder sb = new StringBuilder();
        while ((line = br.readLine()) != null) {
            sb.append(line);
        }
        /*sb为微信返回的xml*/
        String notityXml = sb.toString();
        Map map = PayUtil.doXMLParse(notityXml);
        String returnCode = (String) map.get("return_code");
        String mchId = (String) map.get("mch_id");
        if ("SUCCESS".equals(returnCode)) {
            //验证签名是否正确
            Map<String, String> validParams = PayUtil.paraFilter(map);  //回调验签时需要去除sign和空值参数
            String validStr = PayUtil.createLinkString(validParams);//把数组所有元素，按照“参数=参数值”的模式用“&”字符拼接成字符串
            ServiceBusiness serviceBusiness = serviceBusinessService.getOne(new QueryWrapper<ServiceBusiness>().eq("mch_id", mchId));
            String sign = PayUtil.sign(validStr, serviceBusiness.getMchKey(), "utf-8").toUpperCase();//拼装生成服务器端验证的签名
            //根据微信官网的介绍，此处不仅对回调的参数进行验签，还需要对返回的金额与系统订单的金额进行比对等
            if (sign.equals(map.get("sign"))) {

                log.debug(JSON.toJSONString(map));

                String out_trade_no = (String) map.get("out_trade_no");

                String transaction_id = (String) map.get("transaction_id");
                String coupon_id_0 = (String)map.get("coupon_id_0");
                Long coupon_id = 0L;
                if(StringUtils.isNotBlank(coupon_id_0)){
                    coupon_id = Long.valueOf(coupon_id_0);
                }

                String payOpenid = (String) map.get("openid");
                String time_end = (String) map.get("time_end");

                Long cash_fee = Long.valueOf((String) map.get("cash_fee"));

                /*查询支付临时生成的订单*/
                TOrder orderSingle = tOrderService.selectByOutTradeNo(out_trade_no);
                if (orderSingle != null && orderSingle.getOrderStatus() == 0) {

                    Product product = productService.getOne(
                            new QueryWrapper<Product>().select("id,type,store_id,points,stock_id").eq("id", orderSingle.getProductId()));

                    /*获取门店信息*/
                    Store store = storeService.getById(product.getStoreId());

                    /*获取商户信息*/
                    Merchant merchant = merchantService.getById(store.getMerchantId());

                    if (1 == product.getType()) {/*购买商品积分累加*/
                        memberService.updateIntegral(orderSingle.getOpenid(),product.getPoints());
                    } else if (2 == product.getType()) {/* 2是属于收费优惠卷 */
                        Coupon coupon = new Coupon();
                        coupon.setCouponStockId(product.getStockId());

                        Member member = memberService.selectByOpenid(orderSingle.getOpenid());
                        couponService.quickReceiveCoupon(serviceBusiness, coupon, member, null);
                    }

                    /*
                      如果 coupon_id 不为空，则表示使用了优惠卷购买商品，则需要将该优惠卷进行核销
                      核销优惠卷
                     */
                    if (coupon_id != null) {
                        this.verificationCoupon(coupon_id, store.getWxStoreId(), payOpenid);
                    }

                    /*最后修改订单信息*/
                    TOrder sysOrder = new TOrder();
                    sysOrder.setTransactionId(transaction_id);
                    sysOrder.setRealPayFee(cash_fee);
                    sysOrder.setOrderStatus(1);
                    sysOrder.setExpressStatus(0);
                    sysOrder.setId(orderSingle.getId());
                    sysOrder.setStoreId(store.getId());
                    sysOrder.setStoreName(store.getName());
                    sysOrder.setSubMchId(merchant.getId());
                    sysOrder.setSubMchName(merchant.getName());
                    sysOrder.setTimeEnd(time_end);
                    tOrderService.updateById(sysOrder);

                    /*添加积分*/
                    this.addIntegralDetail(product.getPoints(),orderSingle.getOpenid(),1,6,"购买商品添加积分");
                }
            }
        } else {
            resXml = "<xml>" + "<return_code><![CDATA[FAIL]]></return_code>"
                    + "<return_msg><![CDATA[报文为空]]></return_msg>" + "</xml> ";
        }
        /*响应给微信数据*/
        out = new BufferedOutputStream(
                response.getOutputStream());
        out.write(resXml.getBytes());
        out.flush();
    }

    @Override
    public void wxBusinessCouponNotify(HttpServletRequest request, HttpServletResponse response) throws Exception {
        BufferedOutputStream out = null;
        String resXml = "<xml>" + "<return_code><![CDATA[SUCCESS]]></return_code>"
                + "<return_msg><![CDATA[OK]]></return_msg>" + "</xml> ";
        BufferedReader br = new BufferedReader(new InputStreamReader(request.getInputStream()));
        String line;
        StringBuilder sb = new StringBuilder();
        while ((line = br.readLine()) != null) {
            sb.append(line);
        }
        /*sb为微信返回的xml*/
        String notityXml = sb.toString();
        Map map = PayUtil.doXMLParse(notityXml);
        String returnCode = (String) map.get("return_code");
        String mchId = (String) map.get("mch_id");
        if ("SUCCESS".equals(returnCode)) {
            //验证签名是否正确
            Map<String, String> validParams = PayUtil.paraFilter(map);  //回调验签时需要去除sign和空值参数
            String validStr = PayUtil.createLinkString(validParams);//把数组所有元素，按照“参数=参数值”的模式用“&”字符拼接成字符串
            ServiceBusiness serviceBusiness = serviceBusinessService.getOne(new QueryWrapper<ServiceBusiness>().eq("mch_id", mchId));
            String sign = PayUtil.sign(validStr, serviceBusiness.getMchKey(), "utf-8").toUpperCase();//拼装生成服务器端验证的签名
            //根据微信官网的介绍，此处不仅对回调的参数进行验签，还需要对返回的金额与系统订单的金额进行比对等
            if (sign.equals(map.get("sign"))) {

                log.debug(JSON.toJSONString(map));

                String out_trade_no = (String) map.get("out_trade_no");

                String transaction_id = (String) map.get("transaction_id");
                String coupon_id_0 = (String)map.get("coupon_id_0");
                Long coupon_id = 0L;
                if(StringUtils.isNotBlank(coupon_id_0)){
                    coupon_id = Long.valueOf(coupon_id_0);
                }

                String payOpenid = (String) map.get("openid");
                String time_end = (String) map.get("time_end");

                Long cash_fee = Long.valueOf((String) map.get("cash_fee"));

                /*查询支付临时生成的订单*/
                TOrder orderSingle = tOrderService.selectByOutTradeNo(out_trade_no);
                if (orderSingle != null && orderSingle.getOrderStatus() == 0) {

                    BusinessCoupon product = businessCouponService.getOne(
                            new QueryWrapper<BusinessCoupon>().select("id,type,points,stock_id,belong_merchant").eq("id", orderSingle.getProductId()));

                    /*获取门店信息*/

                    /*获取商户信息*/
                    Merchant merchant = merchantService.getOne(new QueryWrapper<Merchant>().eq("sub_mch_id",product.getBelongMerchant()));
                    memberService.updateIntegral(orderSingle.getOpenid(),product.getPoints());
                    /*
                    if (1 == product.getType()) {*//*购买商品积分累加*//*

                    } else if (2 == product.getType()) {*//* 2是属于收费优惠卷 *//*
                        Coupon coupon = new Coupon();
                        coupon.setCouponStockId(product.getStockId());

                        Member member = memberService.selectByOpenid(orderSingle.getOpenid());
                        couponService.quickReceiveCoupon(serviceBusiness, coupon, member, null);
                    }*/

                    /*
                      如果 coupon_id 不为空，则表示使用了优惠卷购买商品，则需要将该优惠卷进行核销
                      核销优惠卷
                     */
                    /*if (coupon_id != null) {
                        this.verificationCoupon(coupon_id, store.getWxStoreId(), payOpenid);
                    }*/

                    /*最后修改订单信息*/
                    TOrder sysOrder = new TOrder();
                    sysOrder.setTransactionId(transaction_id);
                    sysOrder.setRealPayFee(cash_fee);
                    sysOrder.setOrderStatus(1);
                    sysOrder.setExpressStatus(0);
                    sysOrder.setId(orderSingle.getId());
                    sysOrder.setSubMchId(merchant.getId());
                    sysOrder.setSubMchName(merchant.getName());
                    sysOrder.setTimeEnd(time_end);
                    tOrderService.updateById(sysOrder);

                    /*添加积分*/
                    this.addIntegralDetail(product.getPoints(),orderSingle.getOpenid(),1,8,"购买商家券添加积分");

                    stringRedisTemplate.opsForValue().set(out_trade_no, product.getId()+"", 2, TimeUnit.HOURS);
                }
            }
        } else {
            resXml = "<xml>" + "<return_code><![CDATA[FAIL]]></return_code>"
                    + "<return_msg><![CDATA[报文为空]]></return_msg>" + "</xml> ";
        }
        /*响应给微信数据*/
        out = new BufferedOutputStream(
                response.getOutputStream());
        out.write(resXml.getBytes());
        out.flush();
    }

    @Override
    public void getBusinessCouponNotify(HttpServletRequest request, HttpServletResponse response) throws Exception {

    }

    @Override
    public String refund(TOrder tOrder, String miniAppId, String orderId, HttpServletRequest request) throws WxPayException, Exception {
        WxPayRefundRequest wxPayRefundRequest = new WxPayRefundRequest();

        Product product = productService.getById(tOrder.getProductId());
        int fee = tOrder.getOrderTotalFee();
        /*实际应退款金额*/
        Long realPayFee = tOrder.getRealPayFee();
        if (fee != realPayFee) {
            return "noAuth";
        }
        Store store = storeService.getById(product.getStoreId());
        Merchant merchant = merchantService.getById(store.getCode().split("-")[2]);
        wxPayRefundRequest.setSubAppId(miniAppId);
        wxPayRefundRequest.setSubMchId(merchant.getSubMchId());
        wxPayRefundRequest.setOutTradeNo(tOrder.getOutTradeNo());
        String outRefundNo = System.currentTimeMillis() + "";
        wxPayRefundRequest.setOutRefundNo(outRefundNo);

        wxPayRefundRequest.setTotalFee(fee);
        wxPayRefundRequest.setRefundFee(fee);
        WxPayRefundResult refund = null;
        try {
            Company company = companyService.selectByMiniAppid(miniAppId);
            refund = wxPayServer.getWxPayService(company.getBusinessServiceId()).refund(wxPayRefundRequest);
            String resultCode = refund.getResultCode();
            /*退款返回成功，将数据写到退款记录表中*/
            if ("SUCCESS".equalsIgnoreCase(resultCode)) {
                /*还原商品总数+1*/
                Product reProduct = new Product();
                reProduct.setId(product.getId());
                reProduct.setUsableProductCount(product.getUsableProductCount() + 1);
                productService.updateById(reProduct);

                /*修改订单状态，置为已退款状态*/
                TOrder reOrder = new TOrder();
                reOrder.setId(tOrder.getId());
                reOrder.setOrderStatus(3);
                tOrderService.updateById(reOrder);

                /*会员积分减2*/
                //memberService.updateReduceIntegralByOpenid(tOrder.getOpenid());

                this.addIntegralDetail(product.getPoints(),tOrder.getOpenid(),0,7,"购买商品退款,积分扣除");
            } else {
                return JSON.toJSONString(refund);
            }
        } catch (WxPayException e) {
            log.error("refund", e);
            throw e;
        }
        return "success";
    }

    @Override
    public String businessRefund(TOrder tOrder, String miniAppId, String orderId, HttpServletRequest request) throws WxPayException, Exception {
        WxPayRefundRequest wxPayRefundRequest = new WxPayRefundRequest();

        BusinessCoupon product = businessCouponService.getById(tOrder.getProductId());
        int fee = tOrder.getOrderTotalFee();
        /*实际应退款金额*/
        /*Long realPayFee = tOrder.getRealPayFee();
        if (fee != realPayFee) {
            return "noAuth";
        }*/

        wxPayRefundRequest.setSubAppId(miniAppId);
        wxPayRefundRequest.setSubMchId(product.getBelongMerchant());
        wxPayRefundRequest.setOutTradeNo(tOrder.getOutTradeNo());
        String outRefundNo = System.currentTimeMillis() + "";
        wxPayRefundRequest.setOutRefundNo(outRefundNo);

        wxPayRefundRequest.setTotalFee(fee);
        wxPayRefundRequest.setRefundFee(fee);
        WxPayRefundResult refund = null;
        try {
            Company company = companyService.getById(product.getCompanyId());
            refund = wxPayServer.getWxPayService(company.getBusinessServiceId()).refund(wxPayRefundRequest);
            String resultCode = refund.getResultCode();
            /*退款返回成功，将数据写到退款记录表中*/
            if ("SUCCESS".equalsIgnoreCase(resultCode)) {
                /*还原商品总数+1*/
                BusinessCoupon reProduct = new BusinessCoupon();
                reProduct.setId(product.getId());
                reProduct.setUsableBusinessCouponCount(product.getUsableBusinessCouponCount() + 1);
                businessCouponService.updateById(reProduct);

                /*修改订单状态，置为已退款状态*/
                TOrder reOrder = new TOrder();
                reOrder.setId(tOrder.getId());
                reOrder.setOrderStatus(3);
                tOrderService.updateById(reOrder);

                /*会员积分减2*/
                //memberService.updateReduceIntegralByOpenid(tOrder.getOpenid());

                this.addIntegralDetail(product.getPoints(),tOrder.getOpenid(),0,7,"购买团购券退款,积分扣除");
            } else {
                return JSON.toJSONString(refund);
            }
        } catch (WxPayException e) {
            log.error("refund", e);
            throw e;
        }
        return "success";
    }

    @Override
    public Integer exchangePoints(Product product,String miniAppId,Member member) throws Exception {
        WxPayCouponSendRequest request = WxPayCouponSendRequest.newBuilder().build();
        request.setCouponStockId(product.getStockId());
        request.setOpenidCount(1);
        request.setPartnerTradeNo(System.currentTimeMillis() + "");

        String strOpenid = stringRedisTemplate.opsForValue().get(member.getMiniOpenid());
        log.debug(member.getMiniOpenid() + "==" + strOpenid);
        request.setOpenid(strOpenid);
        request.setNonceStr(System.currentTimeMillis() + "");
        Company company = companyService.selectByMiniAppid(miniAppId);
        WxPayCouponSendResult data = wxPayServer.getWxPayService(company.getBusinessServiceId()).sendCoupon(request);
        log.debug("data.getRetCode()==" + data.getRetCode());
        if ("SUCCESS".equals(data.getRetCode())) {
            MemberCoupon memberCoupon = new MemberCoupon();
            memberCoupon.setWxCouponId(Long.valueOf(data.getCouponId()));
            memberCoupon.setOpenid(member.getMiniOpenid());
            memberCoupon.setMemberId(member.getId());
            //memberCoupon.setOutShopId("");
            memberCouponService.save(memberCoupon);

            this.addIntegralDetail(product.getValue(),member.getMiniOpenid(),0,2,"积分兑换");
        }
        return 1;
    }

    /**
     * 核销优惠券
     */
    private void verificationCoupon(Long coupon_id, String outShopId, String payOpenid) {
        QueryWrapper<MemberCoupon> queryWrapper = new QueryWrapper<>();
        queryWrapper.eq("wx_coupon_id", coupon_id);
        MemberCoupon memberCoupon = new MemberCoupon();
        //memberCoupon.setWxCouponId(coupon_id);
        memberCoupon.setState(1);
        memberCoupon.setOutShopId(outShopId);
        memberCoupon.setPayOpenid(payOpenid);
        memberCouponService.update(memberCoupon, queryWrapper);
    }

    /**
     * 积分明细添加
     */
    private void addIntegralDetail(Integer integral,String openid,Integer status,Integer type,String remark){
        IntegralDetail integralDetail = new IntegralDetail();
        /*积分操作,1,添加；0，扣除*/
        integralDetail.setStatus(status);
        /*购买商品添加积分*/
        integralDetail.setType(type);
        integralDetail.setIntegral(integral);
        integralDetail.setOpenId(openid);
        integralDetail.setRemark(remark);
        integralDetailService.save(integralDetail);
    }
}
